package com.tevintao.marketingsystem.xposted;

import android.content.Context;
import android.os.Process;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewStub;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import com.tevintao.marketingsystem.activity.MainActivity;
import com.tevintao.marketingsystem.log.LogManager;
import com.tevintao.marketingsystem.services.MockServices;
import com.tevintao.marketingsystem.task.WxUiViewConfig;
import com.tevintao.marketingsystem.tool.PackageTool;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;


public class HookWindowManagerGlobal {

    public static final String TAG = HookWindowManagerGlobal.class.getSimpleName();

    public static final String TAG_RETURN_GET_VIEW = "return_get_view";
    public static final String TAG_DO_VIEW_EVENT = "do_view_event";

    public static final String KEY_VIEW_JSON_STRING = "key_view_json_string";


    private static HookWindowManagerGlobal ourInstance = new HookWindowManagerGlobal();

    public static HookWindowManagerGlobal getInstance() {
        return ourInstance;
    }


    public static final String KEY_PRINT_GET_VIEW_JSON = "KEY_PRINT_GET_VIEW_JSON";


    //--------------------------------------------------------------------------------------------------------------
    private Object mWindowManagerGlobal = null;

    private HookWindowManagerGlobal() {
    }

    private Object getWindowManagerGlobal() {
        if (null == mWindowManagerGlobal) {
            mWindowManagerGlobal = getWindowManagerInstance();
        }
        return mWindowManagerGlobal;
    }

    private Object getWindowManagerInstanceApi15() throws Exception {
        Class<?> windowManager = Class
                .forName("android.view.WindowManagerImpl");
        Field instanceField = windowManager.getDeclaredField("mWindowManager");
        instanceField.setAccessible(true);
        Object instance = instanceField.get(null);
        return instance;
    }

    private Object getWindowManagerInstanceApi14_16() throws Exception {
        Class<?> windowManager = Class
                .forName("android.view.WindowManagerImpl");
        Field instanceField = windowManager.getDeclaredField("sWindowManager");
        instanceField.setAccessible(true);
        Object instance = instanceField.get(null);
        return instance;
    }

    private Object getWindowManagerInstanceApiUp17() throws Exception {
        Class<?> windowManager = Class
                .forName("android.view.WindowManagerGlobal");
        Field instanceField = windowManager.getDeclaredField("sDefaultWindowManager");
        instanceField.setAccessible(true);
        Object instance = instanceField.get(null);
        return instance;
    }

    private Object getWindowManagerInstance() {
        Object instance = null;
        try {
            if (MainActivity.CURRENT_USE_ANDROID_OS_SDK == 14 || MainActivity.CURRENT_USE_ANDROID_OS_SDK == 16) {
                instance = getWindowManagerInstanceApi14_16();
            } else if (MainActivity.CURRENT_USE_ANDROID_OS_SDK >= 17) {
//                LogManager.getInstance().logError(" MainActivity.CURRENT_USE_ANDROID_OS_SDK >= 17 CURRENT_USE_ANDROID_OS_SDK = " + MainActivity.CURRENT_USE_ANDROID_OS_SDK);
                instance = getWindowManagerInstanceApiUp17();
            } else {
                instance = getWindowManagerInstanceApi15();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance can not find cls WindowManagerGlobal");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance NoSuchMethodException");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance InvocationTargetException");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance IllegalAccessException");
        } catch (Exception e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance Exception");
        }
        return instance;
    }

    private Object getWindowManagerGlobalInstance() {
        try {
            Class cls = Class.forName("android.view.WindowManagerGlobal");
            LogManager.getInstance().logInfo("cls = " + cls);
            Method instanceMethod = cls.getMethod("getInstance");
            instanceMethod.setAccessible(true);
            Object instance = instanceMethod.invoke(null);
            return instance;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance can not find cls WindowManagerGlobal");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance NoSuchMethodException");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance InvocationTargetException");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getWindowManagerGlobalInstance IllegalAccessException");
        }
        return null;
    }

    public List<View> getRootView() {
        Object global = getWindowManagerGlobal();
        if (null == global) {
            LogManager.getInstance().logError("HookWindowManagerGlobal getViews null == global");
        }
        Object mRootViews = null;
        try {
            Class globalClass = global.getClass();
            Field mViewsField = globalClass.getDeclaredField("mRoots");
            mViewsField.setAccessible(true);
            mRootViews = mViewsField.get(global);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("HookWindowManagerGlobal  NoSuchFieldException mViews " + e.getMessage());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("HookWindowManagerGlobal  IllegalAccessException mViews " + e.getMessage());
        }

        try {
            Object[] views = (Object[]) mRootViews;
            LogManager.getInstance().logInfo("getRootView = " + mRootViews.getClass().isArray() + " size = " + views.length);
        } catch (Exception e) {
            e.printStackTrace();
            LogManager.getInstance().logError("getRootView Exception = " + e);
        }
//        List<View> list;
//        if (null != mRootViews) {
//            try {
//                list = (List<View>) mRootViews;
//                return list;
//            } catch (Exception e) {
//                try {
//                    View[] viewArray = (View[]) mRootViews;
//                    list = new ArrayList();
//                    for (View v : viewArray) {
//                        list.add(v);
//                    }
//                    return list;
//                } catch (Exception arrE) {
//                    LogManager.getInstance().logError("HookWindowManagerGlobal mView is arraylist and is not array  = " + arrE.getMessage());
//                }
//            }
//        }
        return null;
    }

    public List<View> getViews() {
        Object global = getWindowManagerGlobal();
        if (null == global) {
            LogManager.getInstance().logError("HookWindowManagerGlobal getViews null == global");
            return null;
        }
        Object mViews = null;
        try {
            Class globalClass = global.getClass();
            Field mViewsField = globalClass.getDeclaredField("mViews");
            mViewsField.setAccessible(true);
            mViews = mViewsField.get(global);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("HookWindowManagerGlobal  NoSuchFieldException mViews " + e.getMessage());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("HookWindowManagerGlobal  IllegalAccessException mViews " + e.getMessage());
        } catch (Exception e) {
            LogManager.getInstance().logError("HookWindowManagerGlobal  Exception " + e.getMessage());
        }
        List<View> list;
        if (null != mViews) {
            try {
                list = (List<View>) mViews;
                return list;
            } catch (Exception e) {
                try {
                    View[] viewArray = (View[]) mViews;
                    list = new ArrayList();
                    for (View v : viewArray) {
                        list.add(v);
                    }
                    return list;
                } catch (Exception arrE) {
                    LogManager.getInstance().logError("HookWindowManagerGlobal mView is arraylist and is not array  = " + arrE.getMessage());
                }
            }
        }
        return null;
    }

    public View getTopView() {
        List<View> views = getViews();
        if (null == views) {
            return null;
        }
//        LogManager.getInstance().logInfo("getTopView size = " + views.size());
        if (null != views && views.size() > 0) {
            return views.get(views.size() - 1);
        }
        return null;
    }


    public static final String KEY_TOP_CONTEXT_NAME = "KEY_TOP_CONTEXT_NAME";
    public static final String KEY_TOP_CONTEXT_VIEWS = "KEY_TOP_CONTEXT_VIEWS";

    public JSONObject getTopViewJson(boolean isPrint) {
        JSONObject jo = new JSONObject();
        View topView = getTopView();
//        getRootView();
//        LogManager.getInstance().logInfo("getTopViewJson topView = " + topView);
        if (null != topView) {
            Context context = topView.getContext();
            if (null != context) {
                String contextName = context.getClass().getName();
                String topActName = PackageTool.getTopActivityName(context);
                LogManager.getInstance().logInfo("many process top act name = " + topActName + " contextName = " + contextName + "  myUid = " + Process.myUid() + " myPid = " + Process.myPid() + " processName" + MockServices.getProcessName());
                if (WxUiViewConfig.DIALOG_CLASS.equals(contextName)) {
                    LogManager.getInstance().logError("顶层为对话框，优先处理");
                } else if (TextUtils.isEmpty(topActName) || !topActName.equals(contextName)) {
                    LogManager.getInstance().logError("many process  topActName = " + topActName + " contextName " + contextName);
                    return null;
                }
                try {
                    jo.put(KEY_TOP_CONTEXT_NAME, contextName);
                } catch (JSONException e) {
                    e.printStackTrace();
                    LogManager.getInstance().logError("getViewJson KEY_TOP_CONTEXT_NAME");
                }

                if (topView instanceof ViewGroup) {
                    ViewGroup vg = (ViewGroup) topView;
                    try {
                        JSONObject joTree = GetViewJsonTree(vg, -1);
                        if (isPrint)
                            printViewTreeJson(joTree, 0);
                        jo.put(KEY_TOP_CONTEXT_VIEWS, joTree);
                    } catch (JSONException e) {
                        e.printStackTrace();
                        LogManager.getInstance().logError("getViewJson KEY_TOP_CONTEXT_VIEWS " + e.getMessage());
                    }
                }
            }
        } else {
            return null;
        }
        return jo;
    }

    public static final String KEY_VIEW_GROUP_ARRAY = "KEY_VIEW_GROUP_ARRAY";
    public static final String KEY_VIEW_GROUP_INFO = "KEY_VIEW_GROUP_INFO";
    public static final String KEY_VIEW_ARRAY = "KEY_VIEW_ARRAY";

    public static JSONObject GetViewJsonTree(ViewGroup viewGroup, int index) {
        JSONObject jo = new JSONObject();
        JSONArray groupArray = new JSONArray();
        JSONArray viewArray = new JSONArray();
        JSONObject viewGroupJo = getViewJsonAndIndex(viewGroup, index);

//        viewGroupJo = getViewJson(viewGroup);
        for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
            View childView = viewGroup.getChildAt(i);
            if (childView instanceof ViewGroup) {
                groupArray.put(GetViewJsonTree((ViewGroup) childView, i));
            } else {
//                if (childView instanceof ViewStub) {
//
//                } else {
                viewArray.put(getViewJsonAndIndex(childView, i));
//                }
            }
        }

        if (null != viewGroupJo) {
            try {
                jo.put(KEY_VIEW_GROUP_INFO, viewGroupJo);
            } catch (JSONException e) {
                e.printStackTrace();
                LogManager.getInstance().logError("KEY_VIEW_GROUP_INFO ");
            }
        }


        if (groupArray.length() > 0) {
            try {
                jo.put(KEY_VIEW_GROUP_ARRAY, groupArray);
            } catch (JSONException e) {
                e.printStackTrace();
                LogManager.getInstance().logError("KEY_VIEW_GROUP_ARRAY ");
            }
        }


        if (viewArray.length() > 0) {
            try {
                jo.put(KEY_VIEW_ARRAY, viewArray);
            } catch (JSONException e) {
                e.printStackTrace();
                LogManager.getInstance().logError("KEY_VIEW_ARRAY ");
            }
        }


        return jo;
    }

    private void printViewStub(ViewStub viewStub) {

    }

    public static void printViewTreeJson(JSONObject jo, int hierarchy) {

        if (jo.has(KEY_VIEW_GROUP_INFO)) {
            try {
                JSONObject groupinfo = jo.getJSONObject(KEY_VIEW_GROUP_INFO);
                LogManager.getInstance().logInfo(getPreStr(hierarchy) + groupinfo.toString() + " " + hierarchy + " 层级");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }


        if (jo.has(KEY_VIEW_GROUP_ARRAY)) {
            try {
                JSONArray jsonArray = jo.getJSONArray(KEY_VIEW_GROUP_ARRAY);
                for (int i = 0, len = jsonArray.length(); i < len; i++) {
                    JSONObject childJo = jsonArray.getJSONObject(i);
                    printViewTreeJson(childJo, hierarchy + 1);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        if (jo.has(KEY_VIEW_ARRAY)) {
            try {
                JSONArray jsonArray = jo.getJSONArray(KEY_VIEW_ARRAY);
                for (int i = 0, len = jsonArray.length(); i < len; i++) {
                    JSONObject childJo = jsonArray.getJSONObject(i);
                    LogManager.getInstance().logInfo(getPreStr(hierarchy + 1) + childJo.toString() + " " + (hierarchy + 1) + " 层级");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }


    }

    public static String getPreStr(int step) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < step; i++) {
            sb.append("    ");
        }
        return sb.toString();
    }

    private static void getViewGroupJson(JSONArray jsonArray, ViewGroup vg) {
        for (int i = 0, count = vg.getChildCount(); i < count; i++) {
            View childView = vg.getChildAt(i);
            if (childView instanceof ViewGroup) {
                jsonArray.put(getViewJson(childView));
                getViewGroupJson(jsonArray, (ViewGroup) childView);
            } else {
                jsonArray.put(getViewJson(childView));
            }
        }
    }

    public static final String KEY_CHILD_INDEX = "child_index";
    public static final String KEY_VIEW_ID = "view_id";
    public static final String KEY_PARENT_ID = "parent_id";
    public static final String KEY_TAG = "view_tag";

    public static final String KEY_TEXT_CONTENT = "text_content";
    public static final String KEY_TEXT_COLOR = "text_color";
    public static final String KEY_TEXT_SIZE = "text_size";
    public static final String KEY_CLASS_NAME = "class_name";
    public static final String KEY_HAS_ONCLICK = "has_onclick";

    public static final String KEY_VISIBILITY = "view_visibility";


    public static final String KEY_LIST_VIEW_COUNT = "list_view_child_count";
    public static final String KEY_FIRST_VISIBLE_POSITION = "first_visible_position";
    public static final String KEY_LAST_VISIBLE_POSITION = "last_visible_position";
    public static final String KEY_LIST_VIEW_HEADER_COUNT = "list_view_header_count";
    public static final String KEY_LIST_VIEW_FOOTER_COUNT = "list_view_footer_count";
//    public static final String KEY_LIST_VIEW_LAST_VISUAL = "list_view_last_visual";

    public static final String KEY_EDIT_TEXT_HIT = "edit_text_hit";

    public static final String KEY_CONTENT_DES = "content_des";

    public static final String KEY_CHILD_COUNT = "child_count";

    public static JSONObject getViewJson(View view) {
        JSONObject jo = new JSONObject();
        try {
            jo.put(KEY_VIEW_ID, view.getId());
            jo.put(KEY_HAS_ONCLICK, view.hasOnClickListeners());
            ViewParent parent = view.getParent();
            if (parent != null && parent instanceof View) {
                View pv = (View) parent;
                jo.put(KEY_PARENT_ID, pv.getId());
            } else {
                jo.put(KEY_PARENT_ID, "-1");
            }
            jo.put(KEY_CLASS_NAME, view.getClass().getSimpleName());
            jo.put(KEY_VISIBILITY, view.getVisibility());
            if (!TextUtils.isEmpty(view.getContentDescription())) {
                jo.put(KEY_CONTENT_DES, view.getContentDescription());
            }
            if (view instanceof TextView) {
                TextView tv = (TextView) view;
                jo.put(KEY_TEXT_CONTENT, tv.getText());
                jo.put(KEY_TEXT_COLOR, tv.getTextColors().getDefaultColor());
                jo.put(KEY_TEXT_SIZE, tv.getTextSize());
            }
            if (view instanceof ListView) {
                ListView listView = (ListView) view;
                jo.put(KEY_LIST_VIEW_COUNT, listView.getAdapter().getCount());
                int first = listView.getFirstVisiblePosition();
                jo.put(KEY_FIRST_VISIBLE_POSITION, first);
                int last = listView.getLastVisiblePosition();
                jo.put(KEY_LAST_VISIBLE_POSITION, last);
                int header = listView.getHeaderViewsCount();
                jo.put(KEY_LIST_VIEW_HEADER_COUNT, header);
                int foot = listView.getFooterViewsCount();
                jo.put(KEY_LIST_VIEW_FOOTER_COUNT, foot);
//                int lastVisual = listView.getLastVisiblePosition();
//                jo.put(KEY_LIST_VIEW_LAST_VISUAL, lastVisual);
            }
            if (view instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) view;
                int childCount = vg.getChildCount();
                jo.put(KEY_CHILD_COUNT, childCount);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return jo;
    }

    /**
     * @param view
     * @param index 在父控件下的序列
     * @return
     */
    public static JSONObject getViewJsonAndIndex(View view, int index) {
        JSONObject jo = new JSONObject();
        try {
            jo.put(KEY_CHILD_INDEX, index);
            jo.put(KEY_VIEW_ID, view.getId());
            Object tag = view.getTag();
            if (null != tag) {
                jo.put(KEY_TAG, tag.getClass().getName() + " = " + view.getTag());
            }
            jo.put(KEY_HAS_ONCLICK, view.hasOnClickListeners());
            ViewParent parent = view.getParent();
            if (parent != null && parent instanceof View) {
                View pv = (View) parent;
                jo.put(KEY_PARENT_ID, pv.getId());
            } else {
                jo.put(KEY_PARENT_ID, "-1");
            }
            jo.put(KEY_CLASS_NAME, view.getClass().getSimpleName());
            jo.put(KEY_VISIBILITY, view.getVisibility());
            if (!TextUtils.isEmpty(view.getContentDescription())) {
                jo.put(KEY_CONTENT_DES, view.getContentDescription());
            }
            if (view instanceof TextView) {
                TextView tv = (TextView) view;
                jo.put(KEY_TEXT_CONTENT, tv.getText());
                jo.put(KEY_TEXT_COLOR, tv.getTextColors().getDefaultColor());
                jo.put(KEY_TEXT_SIZE, tv.getTextSize());
            }
            if (view instanceof EditText) {
                EditText editText = (EditText) view;
                String hit = "";
                if (!TextUtils.isEmpty(editText.getHint())) {
                    hit = editText.getHint().toString();
                }
                jo.put(KEY_EDIT_TEXT_HIT, hit);
            }
            if (view instanceof ListView) {
                ListView listView = (ListView) view;
                if (listView.getAdapter() != null)
                    jo.put(KEY_LIST_VIEW_COUNT, listView.getAdapter().getCount());
                int first = listView.getFirstVisiblePosition();
                jo.put(KEY_FIRST_VISIBLE_POSITION, first);
                int last = listView.getLastVisiblePosition();
                jo.put(KEY_LAST_VISIBLE_POSITION, last);
                int header = listView.getHeaderViewsCount();
                jo.put(KEY_LIST_VIEW_HEADER_COUNT, header);
                int foot = listView.getFooterViewsCount();
                jo.put(KEY_LIST_VIEW_FOOTER_COUNT, foot);
            }

            if (view instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) view;
                int childCount = vg.getChildCount();
                jo.put(KEY_CHILD_COUNT, childCount);
            }
        } catch (JSONException e) {
            e.printStackTrace();
            LogManager.getInstance().logError("JSONException e " + e.toString());
        }
        return jo;
    }


}
